import { extend, isObject } from "../shared/index";
import { track, trigger } from "./effect"
import type { target, key } from "./index.d"
import { ReactiveFlags, reactive, readonly } from "./reactive";
/**get函数的类型 */
type getter = (target: target, key: key) => any;
/**set函数的类型 */
type setter = (target: target, key: key, value: any) => boolean;
/**baseHandlers的类型 */
export interface baseHandlers {
    /**getter */
    get: getter
    /**setter */
    set: setter
}
//写在这里是为了只初始化一次，避免每次都要调用一次函数
/**getter函数。 */
const get = creatGetter()
/**setter函数。 */
const set = createSetter()
/**readonly 的 getter */
const readonlyGet = creatGetter(true)
/**shallowReadonly 的 getter */
const shallowReadonlyGet = creatGetter(true, true)

/**创建一个getter 。高阶函数，会返回一个函数，作为Proxy的处理函数
 * @param isReadonly 是否为只读
 * @param shallow 是否是非递归响应式（即不响应式内部属性）
 * @returns getter函数
 */
function creatGetter(isReadonly: boolean = false, shallow: boolean = false): getter {
    /** 返回一个getter函数
    * @param target 需要取值的目标对象
    * @param key 需要获取的值的键值
    * @param receiver 如果target对象中指定了getter，receiver则为getter调用时的this值 
    * @returns target.key 的值
   */
    return function get(target: target, key: key) {
        if (key === ReactiveFlags.IS_REACTIVE) return !isReadonly //isReactive函数的逻辑在这里
        else if (key === ReactiveFlags.IS_READONLY) return isReadonly //isReadonly函数的逻辑在这里

        const res = Reflect.get(target, key)

        if (shallow) return res //如果是非递归Proxy，那么直接return即可，不用做下面的操作

        if (isObject(res)) {//如果 target.key 也是对象，那么我们就要递归调用reactive方法，不断的去创建Proxy
            return isReadonly ? readonly(res) : reactive(res) //根据isReadonly进行递归调用
        }

        if (!isReadonly) track(target, key) //不是readonly才收集依赖
        return res
    }
}

/**创建一个setter */
function createSetter(): setter {
    /** setter函数
      * @param target 需要修改的目标对象
      * @param key 需要修改的值的键值
      * @param value 修改后的值
      * @param receiver 如果遇到 setter，receiver则为setter调用时的this值。
      * @returns 返回一个 Boolean 值表明是否成功设置属性。
     */
    return function set(target: target, key: key, value: any) {
        /**通过反射进行设置键值，拿到返回结果：返回一个 Boolean 值表明是否成功设置属性。 */
        const res = Reflect.set(target, key, value)
        trigger(target, key)
        return res
    }
}

/**普通的Proxy处理器 */
export const mutableHandlers: baseHandlers = { get, set };

/**readonly的Proxy处理器 */
export const readonlyHandlers: baseHandlers = {
    get: readonlyGet,
    set(target, key) {// readonly 的响应式对象不可以修改值 
        console.warn(`设置键值 "${String(key)}" 失败: 目标对象是只读的.`, target);
        return true;
    }
};
/**shallowReadonly的Proxy处理器 */
export const shallowReadonlyHandlers: baseHandlers = extend({}, readonlyHandlers, {//使用我们封装的继承函数，相当于改写 readonlyHandlers
    get: shallowReadonlyGet
})
